package com.zxd.interview.util.dingrobot;

import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author zxd
 * @version v1.0.0
 * @Package : com.dcc.common.utils
 * @Description : 钉钉机器人工具类
 * @Create on : 2021/2/4 00:11
 **/
public class DingRobotUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(DingRobotUtils.class);

    /**
     * 使用参数Url构建
     * @param dingRobotRequest 请求头对象
     * @param msg 请求体
     * @return
     * @throws Exception
     */
    public static DingRobotResponseMsg notifyRobot(DingRequestAble dingRobotRequest, DingRobotRequestBody msg) throws Exception {
        Objects.requireNonNull(dingRobotRequest);
        Objects.requireNonNull(msg);
        return notifyRobot(new DingRobotRequest.Builder()
                .url(dingRobotRequest.getUrl())
                .accessToken(dingRobotRequest.getAccessToken())
                .secret(dingRobotRequest.getSecret())
                .msg(msg)
                .build(),
                System.currentTimeMillis());
    }

    /**
     * 按照自定时间戳进行通知
     *
     * @param dingRobotRequest 钉钉机器人请求
     * @throws Exception
     */
    public static DingRobotResponseMsg notifyRobot(DingRequestAble dingRobotRequest) throws Exception {
        return notifyRobot(dingRobotRequest, System.currentTimeMillis());
    }

    /**
     * 通知方法
     * @param dingRobotRequest
     * @param currentTimeMillis
     * @return
     * @throws Exception
     */
    public static DingRobotResponseMsg notifyRobot(DingRequestAble dingRobotRequest, long currentTimeMillis) throws Exception {
        HttpConfig httpConfig = HttpConfig.buildDefaultHttpConfig(buildRequestUrl(dingRobotRequest, currentTimeMillis),
                JSON.toJSONString(dingRobotRequest.getMsg()));
        return parseResponse(notifyRobot(httpConfig));
    }

    /**
     * 转化为对应对象
     *
     * @param notifyRobot 转化JSON
     * @return
     */
    private static DingRobotResponseMsg parseResponse(String notifyRobot) {
        try {
            return JSON.parseObject(notifyRobot, DingRobotResponseMsg.class);
        } catch (Exception e) {
            LOGGER.error("类型转化失败，失败原因为:{}", e.getMessage());
            throw e;
        }
    }

    private static String notifyRobot(HttpConfig httpConfig) throws Exception {
        String send = "";
        try {
            send = new HttpSendAbleAdapter().sendPostJson(httpConfig);
        } catch (Exception e) {
            LOGGER.error("HTTPClient请求发送失败, 失败原因为:{}", e.getMessage());
            throw e;
        }
        return send;
    }

    private static String buildRequestUrl(DingRequestAble dingRobotRequest, long currentTimeMillis) throws Exception {
        return String.format("%s?%s", dingRobotRequest.getUrl(), buildParamUrl(buildParam(dingRobotRequest, currentTimeMillis)));
    }

    /**
     * 构建请求环境参数
     *
     * @param dingRobotRequest  请求request
     * @param currentTimeMillis 当前时间戳
     * @return
     * @throws Exception
     */
    private static Map<String, Object> buildParam(DingRequestAble dingRobotRequest, long currentTimeMillis) throws Exception {
        Map<String, Object> param = new HashMap<>(3);
        param.put("access_token", dingRobotRequest.getAccessToken());
        param.put("timestamp", currentTimeMillis);
        param.put("sign", generateSign(dingRobotRequest.getSecret(), currentTimeMillis));
        return param;
    }

    /**
     * 根据时间戳和秘钥生成一份签名
     *
     * @param timestamp 时间戳
     * @param secret    秘钥
     * @return
     * @throws Exception
     */
    private static String generateSign(String secret, Long timestamp) throws Exception {
        String stringToSign = timestamp + "\n" + secret;
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
        byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
        return URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
    }

    /**
     * 构建URL参数
     *
     * @param param 请求MAP参数
     * @return
     */
    private static String buildParamUrl(Map<String, Object> param) {
        if (null == param || param.size() == 0) {
            return "";
        }
        StringBuilder result = new StringBuilder();
        param.forEach((key, value) -> {
            result.append(key).append("=").append(value);
            result.append("&");
        });
        result.deleteCharAt(result.length() - 1);
        return result.toString();
    }
}
